package com.goldsprite.gameframeworks.ecs.system;

import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.goldsprite.gameframeworks.ecs.LayerMask;
import com.goldsprite.gameframeworks.ecs.component.IComponent;
import com.goldsprite.gameframeworks.ecs.entity.GObject;
import com.goldsprite.gameframeworks.ecs.enums.ManageMode;
import com.goldsprite.gameframeworks.ecs.system.renderer.Gizmos;
import com.goldsprite.gameframeworks.ecs.system.renderer.SpriteRenderer;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import com.goldsprite.gameframeworks.input.*;
import com.goldsprite.gameframeworks.log.Debug;
import com.goldsprite.gameframeworks.ecs.system.renderer.*;

public class GameSystem {
	private static GameSystem instance;

	// 系统管理
	private final List<BaseSystem> systems = new CopyOnWriteArrayList<>();
	private final Map<Class<? extends BaseSystem>, BaseSystem> systemMap = new HashMap<>();
	private final List<BaseSystem> updateSystems = new ArrayList<>();
	private final List<BaseSystem> fixedUpdateSystems = new ArrayList<>();

	//核心系统
	public static TimeLineTaskSystem timeLineTaskSystem;
	public static PhysicsSystem physicsSystem;
	public static SceneSystem sceneSystem;
	public static AnimatorSystem animatorSystem;
	public static SpriteRenderer spriteRenderer;
	public static Gizmos gizmos;

	//其他属性
	private static final float defaultWorldWidth = 960, defaultWorldHeight = 540;
	public static Viewport worldViewport, uiViewport;
	public static OrthographicCamera worldCamera, uiCamera;
	private boolean paused;
	private static float deltaTime, totalDeltaTime;
	private Vector2 cameraWorldPos = new Vector2();

	// 实体管理
	private final List<GObject> allEntities = new CopyOnWriteArrayList<>();

	// 物理相关
	private float fixedUpdateAccumulator = 0f;
	public static final float FIXED_DELTA_TIME = 1f / 60f; // 60Hz物理更新
	private boolean awaked;
	public final Event<Object> onWake = new Event<>();
	public static boolean drawGizmos = true;

	public GameSystem() {
		this(defaultWorldWidth, defaultWorldHeight);
	}
	public GameSystem(float worldWidth, float worldHeight) {
		this(new FitViewport(worldWidth, worldHeight));
	}

	public GameSystem(Viewport uiViewport) {
		OrthographicCamera worldCamera = new OrthographicCamera(uiViewport.getWorldWidth(), uiViewport.getWorldHeight());
		Viewport worldViewport = new FitViewport(uiViewport.getWorldWidth(), uiViewport.getWorldHeight(), worldCamera);
		init(worldViewport, uiViewport);
	}
	public GameSystem(Viewport worldViewport, Viewport uiViewport) {
		init(worldViewport, uiViewport);
	}

	public void init(Viewport worldViewport, Viewport uiViewport) {
		instance = this;
		setViewport(worldViewport, uiViewport);
		initializeCoreSystems();
	}

	private void initializeCoreSystems() {
		// 创建核心系统（它们会自动注册）
		timeLineTaskSystem = new TimeLineTaskSystem();
		physicsSystem = new PhysicsSystem();//物理必须在逻辑前
		sceneSystem = new SceneSystem();
		animatorSystem = new AnimatorSystem();
		spriteRenderer = new SpriteRenderer();
		gizmos = new Gizmos();

		//Log调试系统执行顺序
		String fixedUpdateSystems = this.systems.stream().filter(s->s.getSystemInfo().type().has(GameSystemInfo.SystemType.FIXED_UPDATE)).map(BaseSystem::getSystemName).collect(Collectors.joining(", "));
		String updateSystems = this.systems.stream().filter(s->s.getSystemInfo().type().has(GameSystemInfo.SystemType.UPDATE)).map(BaseSystem::getSystemName).collect(Collectors.joining(", "));
		Debug.logT("System", "系统优先级》：========");
		Debug.logT("System", "固定逻辑系统：" + fixedUpdateSystems);
		Debug.logT("System", "设备逻辑系统：" + updateSystems);
		Debug.logT("System", "===================");

		// 初始化层系统
		createSpriteLayers();
		createCollisionLayers();

		Debug.logT("System", "GameSystem initialized with " + systems.size() + " systems");
	}

	// 系统注册
	public void registerSystemAtBefore(BaseSystem system, BaseSystem before) {
		int index = systems.indexOf(before);
		registerSystem(system, index);
	}

	public void registerSystemAtAfter(BaseSystem system, BaseSystem after) {
		int index = systems.indexOf(after) + 1;
		registerSystem(system, index);
	}

	public void registerSystem(BaseSystem system) {
		registerSystem(system, -1);
	}

	public void registerSystem(BaseSystem system, int index) {
		if (!instance.systemMap.containsKey(system.getClass())) {
			if (index == -1 || index >= systems.size()) {
				systems.add(system);  // 添加到末尾
			} else if (index < 0) {
				systems.add(0, system);  // 添加到开头
			} else {
				systems.add(index, system);  // 插入到指定位置
			}
			instance.systemMap.put(system.getClass(), system);
			//收集系统
			{
				updateSystems.clear();
				fixedUpdateSystems.clear();

				updateSystems.addAll(systems.stream().filter(s->s.getSystemInfo().type().has(GameSystemInfo.SystemType.UPDATE)).collect(Collectors.toList()));
				fixedUpdateSystems.addAll(systems.stream().filter(s->s.getSystemInfo().type().has(GameSystemInfo.SystemType.FIXED_UPDATE)).collect(Collectors.toList()));
			}
			Debug.logT("System", "System registered: " + system.getSystemName());
		}
	}

	// 获取系统实例
	public static <T extends BaseSystem> T getSystem(Class<T> systemType) {
		return instance != null ? (T) instance.systemMap.get(systemType) : null;
	}

	// 实体管理
	public void registerEntity(GObject entity) {
		if (!allEntities.contains(entity)) {
			allEntities.add(entity);
		}
	}

	public void unregisterEntity(GObject entity) {
		allEntities.remove(entity);
	}

	public List<GObject> getAllEntities() {
		return new ArrayList<>(allEntities);
	}

	public void gameLoop(float delta) {
		Debug.infoT("GameSystem", "系统%s", paused?"暂停":"运行中");

//		//限制最大delta
//		delta = MathUtils.clamp(delta, 0, 1 / 30f);
		deltaTime = delta;
		totalDeltaTime += delta;

		if (!awaked) {
			awaked = true;
			for(BaseSystem system : systems) system.awake();
			sceneSystem.awakeScene();

			onWake.invoke(null);
			return;
		}

		// 固定时间步长更新
		fixedUpdateAccumulator += delta;
		while (fixedUpdateAccumulator >= FIXED_DELTA_TIME) {
			executeFixedUpdateSystems(FIXED_DELTA_TIME);
			fixedUpdateAccumulator -= FIXED_DELTA_TIME;
		}

		// 可变时间步长更新
		executeUpdateSystems(delta);

		// 清理任务
		sceneSystem.executeDestroyTask();
	}

	private void executeFixedUpdateSystems(float delta) {
		for (BaseSystem system : systems) {
			if(system.getSystemInfo().type().has(GameSystemInfo.SystemType.FIXED_UPDATE)) {
				if (paused && !isAlwaysRunningSystem(system)) continue;

				if (system.isEnabled()) {
					system.fixedUpdate(delta);
				}
			}
		}
	}

	private void executeUpdateSystems(float delta) {
		for (BaseSystem system : systems) {
			if(system.getSystemInfo().type().has(GameSystemInfo.SystemType.UPDATE)) {
				if (paused && !isAlwaysRunningSystem(system)) continue;

				if (system.isEnabled()) {
					system.update(delta);
				}
			}
		}
	}

	private void createSpriteLayers() {
		RenderLayerManager.createDefaultGameLayers();
	}

	private void createCollisionLayers() {
		// 创建物理层
		LayerMask.createLayer("Default");
		LayerMask.createLayer("Ground");
		LayerMask.createLayer("Player");
		LayerMask.createLayer("Monster");
		LayerMask.createLayer("Attacker");
		LayerMask.createLayer("Item");

		// 设置碰撞矩阵(collLayerName canCollLayerBits)
		LayerMask.setLayerCollisionAllAlways("Default");
		LayerMask.setLayerCollision("Ground", "Player", "Monster", "Item");
		LayerMask.setLayerCollision("Player", "Attacker", "Item");
		LayerMask.setLayerCollision("Monster", "Attacker");
	}

	// 系统管理方法
	public static void enableSystem(Class<? extends BaseSystem> systemType) {
		BaseSystem system = getSystem(systemType);
		if (system != null) {
			system.setEnabled(true);
		}
	}

	public static void disableSystem(Class<? extends BaseSystem> systemType) {
		BaseSystem system = getSystem(systemType);
		if (system != null) {
			system.setEnabled(false);
		}
	}

	public static boolean isSystemEnabled(Class<? extends BaseSystem> systemType) {
		BaseSystem system = getSystem(systemType);
		return system != null && system.isEnabled();
	}

	public static float getFixedAccumulator() {
		return instance.fixedUpdateAccumulator;
	}

	public void debugSystems() {
		System.out.println("=== GameSystem Debug Info ===");
		System.out.println("Total Systems: " + systems.size());
		System.out.println("Update Systems: " + updateSystems.size());
		System.out.println("Fixed Update Systems: " + fixedUpdateSystems.size());
	}

	// 原有兼容方法
	public static GameSystem getInstance() {
		return instance;
	}

	public static void manageGObject(GObject gobject, ManageMode mode) {
		if (instance != null) {
			switch (mode) {
				case ADD:
					instance.registerEntity(gobject);
					break;
				case REMOVE:
					instance.unregisterEntity(gobject);
					break;
			}
		}
	}

	public static void setViewport(Viewport worldViewport, Viewport uiViewport) {
		GameSystem.worldViewport = worldViewport;
		GameSystem.worldCamera = (OrthographicCamera) worldViewport.getCamera();
		GameSystem.uiViewport = uiViewport;
		GameSystem.uiCamera = (OrthographicCamera) uiViewport.getCamera();

		worldViewport.apply(true);
		uiViewport.apply(true);
	}

	public void addDestroyGObject(GObject gobject) {
		sceneSystem.addDestroyGObject(gobject);
	}

	public void addDestroyComponent(IComponent component) {
		sceneSystem.addDestroyComponent(component);
	}


	public static float getDeltaTime() {
		return deltaTime;
	}
	public static float getTotalDeltaTime() {
		return totalDeltaTime;
	}

	public boolean isPause() {
		return paused;
	}
	public void pauseGameSystem() {
		paused = true;
	}

	public boolean isAwaked(){
		return awaked;
	}

	public void resumeGameSystem() {
		paused = false;
	}

	Sound pickupItemSound;

	public void playSound(String name) {
		if ("pickupItem".equals(name)) {
			if (pickupItemSound != null) {
				pickupItemSound.play();
			}
		}
	}

	public boolean isAlwaysRunningSystem(BaseSystem system) {
		boolean boo = system instanceof RenderSystem;
		return boo;
	}

	public Vector2 getCameraWorldPos() {
		cameraWorldPos.set(worldCamera.position.x, worldCamera.position.y);
		if (uiViewport != null) {
			uiViewport.unproject(cameraWorldPos);
		}
		return cameraWorldPos;
	}

	public void dispose() {
	}

	public void resize(int width, int height) {
		GameSystem.worldViewport.update(width, height);
		GameSystem.uiViewport.update(width, height);
	}
}
